package com.jumper.study.config;

import java.util.Collection;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.util.PathMatcher;

import com.jumper.study.component.JwtAuthenticationTokenFilter;
import com.jumper.study.component.StudyDenieHandler;
import com.jumper.study.component.StudyEntryPoint;

import org.springframework.util.AntPathMatcher;

import jakarta.servlet.http.HttpServletRequest;


@Configuration
@EnableWebSecurity
public class StudySecurityConfiguration {
    private static final Logger LOGGER = LoggerFactory.getLogger(StudySecurityConfiguration.class);
    
    @Autowired
    private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;

    @Autowired
    private StudyEntryPoint studyEntryPoint;

    @Autowired
    private StudyDenieHandler studyDenieHandler;

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http.cors(corsCustomizer -> corsCustomizer.disable())//禁用cors
            //关闭csrf
            .csrf(csrfCustomizer -> csrfCustomizer.disable())
            //关闭session
            .sessionManagement(sessionManagementCustomizer -> sessionManagementCustomizer.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
            //设置验证
            .authorizeHttpRequests(
                authorize -> authorize.requestMatchers("/api/front/orders/**", "/api/front/student/**", "/api/front/my/**").hasAnyAuthority("USER", "ADMIN")
                    .requestMatchers("/api/upload", "api/auth/info", "api/auth/password", "/ws/**").hasAnyAuthority("USER", "ADMIN")
                    .requestMatchers("/api/auth/login", "/api/auth/captcha", "/api/auth/register", "/api/front/home", "/api/front/lesson/**").permitAll()
            )
            //根据访问接口执行动态权限验证
            .authorizeHttpRequests(
                authorize -> authorize.anyRequest().access((authenticationSupplier, requestAuthorizationContext) -> {
                    Collection<? extends GrantedAuthority> authorities = authenticationSupplier.get().getAuthorities();
                    HttpServletRequest request = requestAuthorizationContext.getRequest();
                    LOGGER.info("request:{}:{}:{}", request.getMethod(), request.getRequestURI(), request.getRequestURL());
                    boolean granted = false;
                    PathMatcher pathMatcher = new AntPathMatcher();
                    for(GrantedAuthority auth: authorities) {
                        if (auth.getAuthority().startsWith("ADMIN")) {
                            granted = true;
                            break;
                        }
                        if (pathMatcher.match(auth.getAuthority(), String.format("%s:%s", request.getMethod(), request.getRequestURI()))) {
                            LOGGER.info("auth:{}", auth);
                            granted = true;
                            break;
                        }
                    }
                    return new AuthorizationDecision(granted);
                })
            )
            //自定义失效处理
            .exceptionHandling(exceptionHandlingCustomizer -> exceptionHandlingCustomizer.accessDeniedHandler(studyDenieHandler).authenticationEntryPoint(studyEntryPoint))
            //添加jwt过滤验证
            .addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);

        return http.build();
    }
}
